﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

using agree.schema;

using alib.BitArray;
using alib.Collections;
using alib.Collections.ReadOnly;
using alib.Combinatorics;
using alib.Debugging;
using alib.Enumerable;
using alib.Reflection;
using alib.String;

namespace agree.transfer_prototype
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	[DebuggerDisplay("{ToString(),nq}")]
	public abstract class rel_base : IReadOnlyCollection<NodePtr>
	{
		static int next_id;

		public rel_base(rel_base to_copy)
		{
			this.ix = -1;
			this.id = Interlocked.Increment(ref next_id) - 1;

			if (to_copy != null)
				to_copy.values.CopyTo(this.values, 0);
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		int id;

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public int ix;

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public String Id { get { return String.Format("{0}-{1}", GetType().Name, id.ToString()); } }

		public abstract String RelTypeName { get; }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public static String[] rgfeat = { "LBL", "PRED", "ARG0", "ARG1", "ARG2" };

		protected static int _arg_ix(String arg) { return Array.IndexOf<String>(rgfeat, arg.ToUpper()); }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public type_base[] values = new type_base[rgfeat.Length];

		public IEnumerable<type_base> Values { get { return values.Where(v => v != null); } }

		public NodePtr this[String arg] { get { return new NodePtr(this, _arg_ix(arg)); } }

		public type_base lbl { get { return values[0]; } }
		public type_base pred { get { return values[1]; } }
		public type_base arg0 { get { return values[2]; } }
		public type_base arg1 { get { return values[3]; } }
		public type_base arg2 { get { return values[4]; } }

		public NodePtr this[NodePtr np_other]
		{
			get { return new NodePtr(this, np_other.arg_ix); }
		}

		public int Count
		{
			get
			{
				int c = 0;
				for (int i = 0; i < values.Length; i++)
					if (values[i] != null)
						c++;
				return c;
			}
		}

		public IEnumerator<NodePtr> GetEnumerator()
		{
			for (int i = 0; i < values.Length; i++)
				if (values[i] != null)
					yield return new NodePtr(this, i);
		}

		IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }

		public virtual int MaxWidth
		{
			get { return this.Max(_vp => _vp.node_type.ToString().Length) + 12; }
		}

		public override String ToString() { return "[ " + this.Select(vp => vp.ShortInf.CondenseSpaces()).StringJoin(",  ") + " ]"; }
	};


	[DebuggerDisplay("{ToString(),nq}")]
	public abstract class rule_rel : rel_base
	{
		public rule_rel(rule r, rel_base to_copy)
			: base(to_copy)
		{
			this.r = r;
		}
		public readonly rule r;

		public String LBL { set { r.set_value(this, 0, value); } }
		public String PRED { set { r.set_value(this, 1, value); } }
		public String ARG0 { set { r.set_value(this, 2, value); } }
		public String ARG1 { set { r.set_value(this, 3, value); } }
		public String ARG2 { set { r.set_value(this, 4, value); } }

		public String ToStringEx() { return base.ToString() + " " + r.Name; }
	};

	[DebuggerDisplay("{ToString(),nq}")]
	public class rule_src_rel : rule_rel
	{
		public rule_src_rel(rule r, rel_base to_copy = null)
			: base(r, to_copy)
		{
		}
		public override String RelTypeName { get { return "rule-src-" + ix; } }
	};

	[DebuggerDisplay("{ToString(),nq}")]
	public class rule_tgt_rel : rule_rel
	{
		public rule_tgt_rel(rule r, rel_base to_copy = null)
			: base(r, to_copy)
		{
		}
		public override String RelTypeName { get { return "rule-tgt-" + ix; } }
	};

	[DebuggerDisplay("{ix.ToString().PadRight(2),nq} {ToString(),nq}")]
	public class inp_rel : rel_base
	{
		public inp_rel(__input_mrs inp)
			: base(null)
		{
			this.inp = inp;
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public readonly __input_mrs inp;

		public String LBL { set { inp.set_value(this, 0, value); } }
		public String PRED { set { inp.set_value(this, 1, value); } }
		public String ARG0 { set { inp.set_value(this, 2, value); } }
		public String ARG1 { set { inp.set_value(this, 3, value); } }
		public String ARG2 { set { inp.set_value(this, 4, value); } }

		public override String RelTypeName { get { return "inp-" + ix; } }
	};



	[DebuggerDisplay("{ToString(),nq}")]
	public class locus : rel_base
	{
		public locus()
			: base(null)
		{ }
		public locus(locus to_copy)
			: base(to_copy)
		{
		}
		public override String RelTypeName { get { return "hyp-" + ix; } }
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


	[DebuggerDisplay("{ToString(),nq}")]
	public class _rels<T> : IReadOnlyList<T> where T : rel_base
	{
		public _rels()
		{
			this.arr = Collection<T>.None;
		}
		public _rels(IEnumerable<T> src)
			: this()
		{
			var e = src.GetEnumerator();
			while (e.MoveNext())
				this.Add(e.Current);
		}

		T[] arr;

		public void Add(T t)
		{
			int ix = alib.Array.arr.Append(ref arr, t);
			if (t.ix == -1)
				t.ix = ix;
		}

		public void Remove(T t)
		{
			arr = alib.Array.arr.Remove(arr, t);
		}

		public T this[int index]
		{
			get { return arr[index]; }
		}

		public int Count
		{
			get { return arr.Length; }
		}

		public IEnumerator<T> GetEnumerator()
		{
			return arr.Enumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return arr.Enumerator();
		}
	};
}
